package it.unicam.cs.cosy.bioshape.core.components;

import java.io.Serializable;
import java.util.List;

import javax.vecmath.Matrix3d;
import javax.vecmath.Matrix4d;
import javax.vecmath.Tuple3d;
import javax.vecmath.Vector3d;

import vclip.PolyTree;

import it.unicam.cs.cosy.bioshape.core.components.movers.EntityDriver;
import it.unicam.cs.cosy.bioshape.core.shapes.Bounds;

/**
 * Represents a generic simulation entity. Such entity has a unique ID, a mass,
 * a position, a velocity, a perception area and a bounding volume. It can
 * executed perception driven behaviour as well as collide with other entities
 * in the simulation.
 * 
 * It corresponds to a generic 3D Process in the Shape Calculus
 * 
 * @author Gaston Alanis, Matteo Micheletti, Andrea Piermarteri, Federico Buti
 */
public interface Entity extends Serializable {

    /** First part of an entity name */
    
    final static String SHAPE_NAME_PREFIX = "Shape#";

    /**
     * Updates {@code Entity} position according to its instant velocity. The
     * resulting movement is linear, integrating by the given deltaT step
     * 
     * @param deltaT
     *            time to be multiplied by the instantVelocityVector in order to
     *            integrate the movement
     */
    void move(double deltaT);

    /**
     * Gives the bounding volume of the entity, i.e. a sphere or a box
     * containing the entity.
     * 
     * @return an instance of a bounding volume containing the entity
     */
    Bounds getBounds();

    /**
     * The returned value <i>must</i> be in the reference frame, i.e., it must
     * be defined w.r.t. the global coordinate system of the simulation.
     * 
     * @return The <i>copy</i> of the center vector of the {@code Entity}
     */
    Tuple3d getCenter();

    /**
     * @return The {@code id} of the entity
     */
    long getId();

    /**
     * @return the {@code mass} of the shape
     */
    double getMass();

    /**
     * @return {@code true} if the {@code Entity} has been involved in a
     *         collision, {@code false} otherwise
     */
    boolean isCollided();

    /**
     * Generates a set of data for the {@code LocalCoordinator}. The data is
     * compound of {@code Service} class files and input data required to
     * execute specific tasks provided by the {@code Service} objects
     * themselves. The basic implementation of {@code ShapedEntity} provides
     * just perception of the overall world around the shape. This information
     * can be used by the {@code EntityDriver} object, if it is necessary for
     * calculating the next velocity.
     * 
     * @see ShapedEntity
     * @see EntityDriver
     */
    void ncdInteractions();

    /**
     * @param center
     *            the new centre for the entity
     */
    void setCenter(Tuple3d center);

    /**
     * Set to {@code true} if the {@code Entity} is involved in a collision
     * 
     * @param collided
     *            status of the entity in the current iteration
     */
    void setCollided(boolean collided);

    /**
     * Overcomes the {@code Entity#updateVelocity(EntityDriver)} method and
     * changes <i>translation</i> velocity to a specific value. Exploited for
     * collision response.
     * 
     * @param newInstantVelocity
     *            new instant velocity vector for the entity
     */
    void setInstantVelocity(Vector3d newInstantVelocity);

    /**
     * Overcomes the {@code Entity#updateVelocity(EntityDriver)} method and
     * changes <i>rotation</i> velocity to a specific value. Exploited for
     * collision response.<br>
     * WARNING: The passed values must be expressed in radians since the method
     * <i>does not</i> execute any conversion from {@code degrees} to
     * {@code radians}.
     * 
     * 
     * @param newInstantAngularVelocity
     *            new instant angular velocity pseudovector for the entity -
     *            Used Rotation Representation: fixed axis Roll, Pitch, Yaw
     *            about X, Y, Z axes respectively, typical for angular
     *            velocities
     */
    void setInstantAngularVelocity(Vector3d newInstantAngularVelocity);

    /**
     * Sets or Updates the driver for the entity.
     * 
     * @param entityDriver
     *            The new {@code EntityDriver} associated to the {@code Entity}
     */
    void setDriver(EntityDriver entityDriver);

    /**
     * @return <i>Copy</i> of the currently set translation vector for the
     *         entity
     * 
     */
    Vector3d getInstantVelocity();

    /**
     * @return A list of the {@code Entity} shapes of which this {@code Entity}
     *         is composed of. If the {@code Entity} is <i>atomic</i> there are
     *         <i>no</i> components.
     */
    List<PolyTree> getComponentEntities();

    /**
     * @return The {@code String} which identify in the input the 3D shape
     *         associated with this {@code Entity}.
     */
    String getGeometry();

    /**
     * Returns the transformation from this Entity's PolyTree's local frame to
     * its reference frame.
     * 
     * @return transform from local frame to reference frame
     */
    public Matrix4d getTransform();

    /**
     * @return <i>Copy</i> of the current Angular velocity pseudovector for the
     *         shape (automatically converted in radians) - Used Rotation
     *         Representation: fixed axis roll, pitch, yaw about X, Y, Z axes
     *         respectively, typical for angular velocities
     */
    Vector3d getInstantAngularVelocity();

    /**
     * Updates the velocity of the entity, in the current interaction, on the
     * basis of the passed driver object<br>
     * WARNING: the general contract of the method requires that the rotation
     * velocity is already expressed in radians since the method <i>does not</i>
     * apply any type of conversion from {@code degrees} to {@code radians}.
     */
    void updateVelocity();

    // TODO le sottoclassi chiamano questo metodo previa verifica della flag
    // "collided". Il metodo chiama l'esecuzione del driver, passandogli le
    // informazioni di interesse raccolte da ncdInteraction() o altro
    // Object parameter[] = { getVelocity() };
    // velocity = driver.calculateTranslation(parameter);

    /**
     * Executes the binding between this {@code Entity} and the passed one. Code
     * must correctly handle the geometry binding.
     * 
     * @param e
     *            The {@code Entity} to be connected
     */
    void join(Entity e);

    /**
     * Executes the splitting of a previously established bond
     */
    void split();

    /**
     * Gets the name of this Entity.
     * 
     * @return name of this PolyTree
     */
    public String getName();

    /**
     * @return The inertia tensor of this shape, usually in local frame
     *         coordinates.
     */
    public Matrix3d getInertiaTensor();

    /**
     * Builds a request to the services available in the simulated environment.
     * The {@code LocalCoordination} which owns the {@code Entity} directly
     * queries the {@code Service} objects on the basis of the input built by
     * this method.
     * 
     * @return A {@code ShapeRequest} object containing the selected
     *         {@code Service}s to query and the relative input
     */
    ShapeRequest queryServices();

    /**
     * Checks if the {@code Entity} is compound or simple. A compound
     * {@code Entity} is the result of a clash of entities on compatible
     * geometric features.
     * 
     * @return {@code true} if the {@code Entity} is compound, {@code false}
     *         otherwise
     */
    boolean isAtomicEntity();
}